#include "mytcpproxy.h"
#include "mywidgetfactory.h"
#include "myconfig.h"
#include <QTcpSocket>
#include <QDebug>
#include "imageutil.h"
#include <QFile>

MyTcpProxy::MyTcpProxy()
{
    //
    socket=new QTcpSocket();
    //
    QString hostname = MyConfig::getConfigString("network/host");
    int port = MyConfig::getConfigInt("network/port");
    qDebug() << hostname << ", " << port;
    //连接
    socket->connectToHost(hostname,port);
    //绑定槽函数
    QObject::connect(socket, &QTcpSocket::readyRead, this, &MyTcpProxy::msgRecved,Qt::QueuedConnection);
    QObject::connect(socket, &QTcpSocket::disconnected, this, &MyTcpProxy::onDisconn);
    //绑定返回报文的类型 与 各界面的UI处理的槽函数
    QObject::connect(this, &MyTcpProxy::loginRet, MyWidgetFactory::getLoginWidget(),&LoginWidget::onLoginRet);
    QObject::connect(this, &MyTcpProxy::regRet, MyWidgetFactory::getRegistWidget(),&RegistWidget::onMsgRecv);
    QObject::connect(this, &MyTcpProxy::devListRet, MyWidgetFactory::getMainWidget(),&MainWidget::onDevListRet);
    QObject::connect(this, &MyTcpProxy::devDelRet, MyWidgetFactory::getMainWidget(),&MainWidget::onDevDelRet);
    QObject::connect(this, &MyTcpProxy::devAddRet, MyWidgetFactory::getAddDeviceWidget(),&AddDeviceWidget::onDevAdd);
    QObject::connect(this, &MyTcpProxy::startCameraRet, MyWidgetFactory::getMainWidget(),&MainWidget::onStartCameraRet);
    QObject::connect(this, &MyTcpProxy::stopCameraRet, MyWidgetFactory::getMainWidget(),&MainWidget::onStopCameralRet);
    QObject::connect(this, &MyTcpProxy::videoRecv, MyWidgetFactory::getMainWidget(),&MainWidget::onVideoRecv);
}

MyTcpProxy *MyTcpProxy::getTcpProxy()
{
    static MyTcpProxy* instance=new MyTcpProxy();
    return instance;
}

//槽函数，从tcp socket收到消息
void MyTcpProxy::msgRecved()
{
    while(socket->bytesAvailable()){
        qDebug() << "1111:: tcp:::  msgRecved!";
        //解析报文
        MsgPack pack=MsgPack::socket2MsgPack(socket);
        qDebug() << "2222::" << pack.type;
        //
        if(pack.type == MsgPack::PACK_LOGIN_RET){
            int ret=*((int*)pack.getField(0).contentArr.data());
            emit loginRet(ret, "");
            return;
        }
        if(pack.type == MsgPack::PACK_REG_RET){
            int ret=*((int*)pack.getField(0).contentArr.data());
            emit regRet(ret, "");
            return;
        }
        if(pack.type == MsgPack::PACK_DEVLIST_RET){
            int ret=*((int*)pack.getField(0).contentArr.data());
            QVector<QVector<QString>> tableDatas;
            for(unsigned int i=1;i<pack.filedNum;i+=4){
                QVector<QString> row;
                row << QString(pack.getField(i).contentArr.data());
                row << QString(pack.getField(i+1).contentArr.data());
                row << QString(pack.getField(i+2).contentArr.data());
                row << QString(pack.getField(i+3).contentArr.data());
                tableDatas << row;
            }
            emit devListRet(ret, tableDatas);
            return;
        }
        if(pack.type == MsgPack::PACK_DEV_ADD_RET){
            int ret=*((int*)pack.getField(0).contentArr.data());
            emit devAddRet(ret, "");
            return;
        }
        if(pack.type == MsgPack::PACK_DEV_DEL_RET){
            int ret=*((int*)pack.getField(0).contentArr.data());
            emit devDelRet(ret, "");
            return;
        }
        if(pack.type == MsgPack::PACK_START_CAMERA_RET){
            int ret=*((int*)pack.getField(0).contentArr.data());
            emit startCameraRet(ret, "");
            return;
        }
        if(pack.type == MsgPack::PACK_STOP_CAMERA_RET){
            int ret=*((int*)pack.getField(0).contentArr.data());
            emit stopCameraRet(ret, "");
            return;
        }
        static QByteArray byteArr;
        if(pack.type == MsgPack::PACK_DEV_VEDIO){
            qDebug() << "收到了视频流报文";
            //处理
            //devid
            QString devid = QString(pack.getField(0).contentArr.data());
            //total
            int total=*((int*)pack.getField(1).contentArr.data());
            //packno
            int packno=*((int*)pack.getField(2).contentArr.data());
            //byte[]
            int arrLen = pack.getField(3).contentLen;
            for(int i=0;i<arrLen;i++)
                byteArr.push_back(pack.getField(3).contentArr.data()[i]);
            qDebug() << "packno=["<< packno <<"], byteArr.size=["<< byteArr.size()<<"]";
            //        unsigned int crc=0;
            //        for(int i=0;i<100;i++){
            //            printf("%02X ", (unsigned char)pack.getField(3).contentArr.data()[i]);
            //            crc += (unsigned char)pack.getField(3).contentArr.data()[i];
            //        }
            //        printf("\ncrc=[%ud]\n", crc);
            if(packno+1 >= total){
                qDebug() << "收齐了一帧图片";
                //            static int num=0;
                QImage image = ImageUtil::yuyvArr2QImage((const uchar*)byteArr.data(),160,120);
                QPixmap pic = QPixmap::fromImage(image);
                //            QFile file("C:/Users/zhuorui/Desktop/1/pic_"+QString(num++));
                //            file.open(QFile::WriteOnly);
                //            file.write(byteArr);
                //            file.flush();
                //            file.close();
                //
                byteArr.clear();
                emit videoRecv(pic);
            }
            //
            sndVideoRet("","");//回复一下
        }
    }
    return;
}

//槽函数，tcp连接断开
void MyTcpProxy::onDisconn()
{
    qDebug() << "tcp:::  onDisconn!";
}


bool MyTcpProxy::sndLogin(const QString & user, const QString & pwd)
{
    MyTcpProxy* proxy = MyTcpProxy::getTcpProxy();
    //
    MsgPack pack(MsgPack::pack_t::PACK_LOGIN);
    pack.addStringField(user.size(),user.toLocal8Bit().data());
    pack.addStringField(pwd.size(),pwd.toLocal8Bit().data());
    QVector<char> buf=pack.pack2Buffer();
    //    qDebug() << "buf.size=" << buf.length();
    int ret=proxy->socket->write(buf.data(), buf.size());
    proxy->socket->flush();
    //    qDebug() << "已经发送消息 ret=" << ret;
    return true;
}

bool MyTcpProxy::sndReg(const QString &user, const QString &pwd)
{
    MyTcpProxy* proxy = MyTcpProxy::getTcpProxy();
    //
    MsgPack pack(MsgPack::pack_t::PACK_REG);
    //
    //    qDebug() << "user=["<< user << "]";
    //    for(int i=0;i<user.size();i++){
    //        qDebug() << (int)user.toLocal8Bit().data()[i] << " " << user[i].unicode();
    //    }
    //    qDebug() << "**********************";

    pack.addStringField(user.size(),user.toLocal8Bit().data());
    pack.addStringField(pwd.size(),pwd.toLocal8Bit().data());
    QVector<char> buf=pack.pack2Buffer();
    //    qDebug() << "buf.size=" << buf.length();
    int ret=proxy->socket->write(buf.data(), buf.size());
    proxy->socket->flush();
    //    qDebug() << "已经发送消息 ret=" << ret;
    return true;
}

bool MyTcpProxy::sndGetDevList(const QString &userid)
{
    MyTcpProxy* proxy = MyTcpProxy::getTcpProxy();
    //
    MsgPack pack(MsgPack::pack_t::PACK_DEVLIST);
    //
    //    qDebug() << "**********************";

    pack.addStringField(userid.size(),userid.toLocal8Bit().data());
    QVector<char> buf=pack.pack2Buffer();
    //    qDebug() << "buf.size=" << buf.length();
    int ret=proxy->socket->write(buf.data(), buf.size());
    proxy->socket->flush();
    //    qDebug() << "已经发送消息 ret=" << ret;
    return true;
}

bool MyTcpProxy::sndDevAdd(const QString &userid, const QString &devid, const QString &devname, const QString &desc)
{
    MyTcpProxy* proxy = MyTcpProxy::getTcpProxy();
    //
    MsgPack pack(MsgPack::pack_t::PACK_DEV_ADD);
    //
    pack.addStringField(userid.size(),userid.toLocal8Bit().data());
    pack.addStringField(devid.size(),devid.toLocal8Bit().data());
    pack.addStringField(devname.size(),devname.toLocal8Bit().data());
    pack.addStringField(desc.size(),desc.toLocal8Bit().data());
    QVector<char> buf=pack.pack2Buffer();
    //    qDebug() << "buf.size=" << buf.length();
    int ret=proxy->socket->write(buf.data(), buf.size());
    proxy->socket->flush();
    //    qDebug() << "已经发送消息 ret=" << ret;
    return true;
}

bool MyTcpProxy::sndDevDel(const QString &userid, const QString &devid)
{
    MyTcpProxy* proxy = MyTcpProxy::getTcpProxy();
    //
    MsgPack pack(MsgPack::pack_t::PACK_DEV_DEL);
    //
    pack.addStringField(userid.size(),userid.toLocal8Bit().data());
    pack.addStringField(devid.size(),devid.toLocal8Bit().data());
    QVector<char> buf=pack.pack2Buffer();
    //    qDebug() << "buf.size=" << buf.length();
    int ret=proxy->socket->write(buf.data(), buf.size());
    proxy->socket->flush();
    //    qDebug() << "已经发送消息 ret=" << ret;
    return true;
}

bool MyTcpProxy::sndStartCamera(const QString &userid, const QString &devid)
{
    MyTcpProxy* proxy = MyTcpProxy::getTcpProxy();
    //
    MsgPack pack(MsgPack::pack_t::PACK_START_CAMERA);
    //
    pack.addStringField(userid.size(),userid.toLocal8Bit().data());
    pack.addStringField(devid.size(),devid.toLocal8Bit().data());
    QVector<char> buf=pack.pack2Buffer();
    //    qDebug() << "buf.size=" << buf.length();
    int ret=proxy->socket->write(buf.data(), buf.size());
    proxy->socket->flush();
    //    qDebug() << "已经发送消息 ret=" << ret;
    return true;
}

bool MyTcpProxy::sndStopCamera(const QString &userid, const QString &devid)
{
    MyTcpProxy* proxy = MyTcpProxy::getTcpProxy();
    //
    MsgPack pack(MsgPack::pack_t::PACK_STOP_CAMERA);
    //
    pack.addStringField(userid.size(),userid.toLocal8Bit().data());
    pack.addStringField(devid.size(),devid.toLocal8Bit().data());
    QVector<char> buf=pack.pack2Buffer();
    qDebug() << "buf.size=" << buf.length();
    int ret=proxy->socket->write(buf.data(), buf.size());
    proxy->socket->flush();
    qDebug() << "已经发送消息 ret=" << ret;
    return true;
}

bool MyTcpProxy::sndVideoRet(const QString &userid, const QString &devid)
{
    qDebug() << "发送了 video的ret报文";
    MyTcpProxy* proxy = MyTcpProxy::getTcpProxy();
    //
    MsgPack pack(MsgPack::pack_t::PACK_DEV_VEDIO_RET);
    //
    pack.addStringField(userid.size(),userid.toLocal8Bit().data());
    pack.addStringField(devid.size(),devid.toLocal8Bit().data());
    QVector<char> buf=pack.pack2Buffer();
    int ret=proxy->socket->write(buf.data(), buf.size());
    proxy->socket->flush();
    return true;
}

int MyTcpProxy::getAvailCnt()
{
    return MyTcpProxy::getTcpProxy()->socket->bytesAvailable();
}

MsgField::MsgField(unsigned int contentLen, char* arr)
{
    this->contentLen = contentLen;
    for(unsigned int i=0;i<contentLen;i++)
        contentArr.push_back(arr[i]);
}

void MsgField::pushByte(char byte)
{
    contentArr.push_back(byte);
    contentLen++;
}

MsgPack::MsgPack(MsgPack::pack_t type):totalLen(12),type(type),filedNum(0)
{
}

void MsgPack::addStringField(int contentLen, char *content)
{
    MsgField field(contentLen, content);
    field.pushByte(0);//字符串的结尾
    fields.push_back(field);
    filedNum++;
    totalLen+=4+contentLen;
}

void MsgPack::addField(int contentLen, char *content)
{
    MsgField field(contentLen, content);
    fields.push_back(field);
    filedNum++;
    totalLen+=4+contentLen;
}

MsgField MsgPack::getField(int index)
{
    return fields[index];
}

QVector<char> MsgPack::pack2Buffer()
{
    QVector<char> arr;
    char buf[12];
    memcpy(buf, &totalLen, 4);
    memcpy(buf+4, &type, 4);
    memcpy(buf+8, &filedNum, 4);
    for(int i=0;i<12;i++)
        arr.push_back(buf[i]);
    //
    for(unsigned int i=0;i<filedNum;i++){
        MsgField f = fields[i];
        char buf[4];
        memcpy(buf, &f.contentLen, 4);
        for(int j=0;j<4;j++)
            arr.push_back(buf[j]);
        for(unsigned int j=0;j<f.contentLen;j++)
            arr.push_back(f.contentArr[j]);
    }
    return arr;
}

MsgPack MsgPack::socket2MsgPack(QTcpSocket *socket)
{
    //长度
    int totalLen;
    socket->read((char*)&totalLen, 4);
    //报文类型
    pack_t type;
    socket->read((char*)&type, 4);
    //字段数量
    int nums;
    socket->read((char*)&nums, 4);
    //解析字段内容
    MsgPack pack(type);
    for(int i=0;i<nums;i++){
        int contentLen;
        socket->read((char*)&contentLen, 4);
        char buf[contentLen];
        socket->read(buf,contentLen);
        //
        pack.addField(contentLen,buf);
    }
    return pack;
}



